using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using graph;
using System.IO;
using System.Diagnostics;

namespace Lab1
{
    public partial class frmMain : Form
    {
        #region Members

        //WinAPI-Declaration for SendMessage
        [DllImport("user32.dll")]
        public static extern IntPtr SendMessage(
        IntPtr window, int message, int wparam, int lparam);
        const int WM_VSCROLL = 0x115;
        const int SB_BOTTOM = 7;

        Graph curGraph;
        int nodeCount;

        #endregion

        #region Constructor, Destructor

        public frmMain()
        {
            InitializeComponent();
            btnExecute.Enabled = false;
        }

        #endregion

        #region Message Handlers

        // When the Browse button is pressed
        private void btnBrowse_Click(object sender, EventArgs e)
        {
            OpenFileDialog fdlg = new OpenFileDialog();
            fdlg.Title = "Open Bayesian Network Dot File";
            // fdlg.InitialDirectory = @LabDir;
            fdlg.Filter = "DOT files (*.dot)|*.dot|All files (*.*)|*.*";
            fdlg.FilterIndex = 1;
            fdlg.RestoreDirectory = false;
            if (fdlg.ShowDialog() == DialogResult.OK)
            {
                txtFileName.Text = fdlg.FileName;
            }
        }

        // When the Load button is pressed
        private void btnLoad_Click(object sender, EventArgs e)
        {
            // If not file name, then don't do anything.
            if (txtFileName.Text == "")
            {
                System.Windows.Forms.MessageBox.Show("Please select a DOT file to load first!");
                return;
            }

            // First reset images
            pbBefore.Image = null;
            pbAfter.Image = null;

            // Read in DOT file to graph
            Log("Reading DOT file...");
            curGraph = dotParser.DotParser.DotIn(txtFileName.Text);
            Log("Done!\n");

            // Calling external program to generate new gif file
            Log("Creating Bayesian Network image...");
            string strImageFile = txtFileName.Text.Remove(txtFileName.Text.Length - 3) + "gif";
            // Delete gif file if it already exists
            if(File.Exists(strImageFile))
            {
                File.Delete(strImageFile);
            }
            // Generate image now.
            string commandLine = string.Format("-T{0} -o{1} {2}",
                "gif",
                strImageFile,
                txtFileName.Text
                );

            Process proc = new Process();
            proc.StartInfo.WorkingDirectory = @"C:\";
            proc.StartInfo.FileName = AppDomain.CurrentDomain.BaseDirectory + @"bin\dot.exe";
            proc.StartInfo.Arguments = commandLine;
            proc.StartInfo.UseShellExecute = false;
            proc.StartInfo.RedirectStandardOutput = false;
            proc.StartInfo.RedirectStandardError = false;
            proc.Start();
            proc.WaitForExit();
            proc.Close();
            Log("Done!\n");

            // If there's an image file, display it.
            Log("Displaying image before pruning...");
            try
            {
                Stream s = File.Open(strImageFile, FileMode.Open);
                Image before = Image.FromStream(s);
                s.Close();                 
                pbBefore.Image = before;
                Log("Done!\n");
            }
            catch(Exception)
            {
                System.Windows.Forms.MessageBox.Show("Failed to load before image!");
                Log("Failed!\n");
            }

            // Enable the execute button
            btnExecute.Enabled = true;
        }

        // When the Prune Network button is pressed
        private void btnExecute_Click(object sender, EventArgs e)
        {
            // If no graph is loaded, then don't do anything
            if (curGraph == null)
            {
                System.Windows.Forms.MessageBox.Show("Please load a graph first!");
                return;
            }

            // Reset images in case we need to overwrite it
            pbAfter.Image = null;

            Graph prunedGraph = new Graph();
            prunedGraph.Name = curGraph.Name + "_pruned";

            // Loop through all query nodes and union results
            Log("Performing d-seperation on all query nodes:\n");
            foreach(Node q in curGraph.QueryNodes.Values)
            {
                Log("\tQuery node: " + q.Name + "\n");
            
                // Calling the Reachable algorithm
                Log("\tPruning nodes based on d-seperation...");
                prunedGraph.Nodes = prune.DictionaryUnion(prunedGraph.Nodes, prune.Reachable(curGraph, q, curGraph.EvidenceNodes));
                Log("Done!\n");
            }
            // Clean it up
            prunedGraph.EvidenceNodes = curGraph.EvidenceNodes;
            prunedGraph.QueryNodes = curGraph.QueryNodes;
            prunedGraph.Repair();
            // Remember mid step node count
            nodeCount = prunedGraph.Nodes.Count;

            if (!chkdseponly.Checked)
            {
                // Let's store a copy of the prunedGraph here
                Graph prunedGraphCopy = prunedGraph;
                prunedGraph = new Graph();
                prunedGraph.EvidenceNodes = prunedGraphCopy.EvidenceNodes;
                prunedGraph.QueryNodes = prunedGraphCopy.QueryNodes;
                // Calling the non-evidence nodes handler next
                Log("Pruning non-evidence nodes...");
                foreach (Node q in curGraph.QueryNodes.Values)
                {
                    Log("\tQuery node: " + q.Name + "\n");

                    // Calling the Non-evidence Nodes Handler
                    Log("\tPruning nodes based on non-evidence...");
                    prunedGraph.Nodes = prune.DictionaryUnion(prunedGraph.Nodes, prune.NonEvidenceNodesHandler(prunedGraphCopy, q, prunedGraphCopy.EvidenceNodes));
                    Log("Done!\n");
                }
                // Clean it up
                prunedGraph.Repair();
                Log("Done!\n");
            }

            // Exporting DOT file
            Log("Saving pruned network to DOT file...");
            string strOutFile = txtFileName.Text.Remove(txtFileName.Text.Length-4)+"_pruned.dot";
            dotParser.DotParser.DotOut(prunedGraph, strOutFile);
            Log("Done!\n");

            // Calling external program to generate new gif file
            Log("Creating pruned network image...");
            string strImageFile = strOutFile.Remove(strOutFile.Length - 3) + "gif";
            // Delete gif file if it already exists
            if (File.Exists(strImageFile))
            {
                File.Delete(strImageFile);
            }
            // Generate image now.
            string commandLine = string.Format("-T{0} -o{1} {2}",
                "gif",
                strImageFile,
                strOutFile
                );

            Process proc = new Process();
            proc.StartInfo.WorkingDirectory = @"C:\";
            proc.StartInfo.FileName = AppDomain.CurrentDomain.BaseDirectory + @"bin\dot.exe";
            proc.StartInfo.Arguments = commandLine;
            proc.StartInfo.UseShellExecute = false;
            proc.StartInfo.RedirectStandardOutput = false;
            proc.StartInfo.RedirectStandardError = false;
            proc.Start();
            proc.WaitForExit();
            proc.Close();
            Log("Done!\n");

            // If there's an image file, display it.
            Log("Displaying image after pruning...");
            try
            {
                Stream s = File.Open(strImageFile, FileMode.Open);
                Image after = Image.FromStream(s);
                s.Close();                 
                pbAfter.Image = after;
                Log("Done!\n");
            }
            catch (Exception)
            {
                System.Windows.Forms.MessageBox.Show("Failed to load after image!");
                Log("Failed!\n");
            }

            // Let's print out summary
            Log("Summary:\n");
            Log("We started with " + curGraph.Nodes.Count + " nodes;\n");
            int diff = curGraph.Nodes.Count - nodeCount;
            Log("D-sep pruned " + diff.ToString() + " nodes and ended with " + nodeCount.ToString() + " nodes;\n");
            if (!chkdseponly.Checked)
            {
                diff = nodeCount - prunedGraph.Nodes.Count;
                Log("We further pruned " + diff.ToString() + " nodes and ended with " + prunedGraph.Nodes.Count.ToString() + " nodes.\n");
            }

            // Disable this button until load is pressed again
            btnExecute.Enabled = false;
        }

        // When the clear button is pressed
        private void btnClear_Click(object sender, EventArgs e)
        {
            rtxtLog.Clear();
        }

        #endregion

        #region Other Functions

        // Code to display logs in log rich text box (refresh and scroll to bottom)
        private void Log(string str)
        {
            rtxtLog.AppendText(str);
            rtxtLog.Refresh();
            SendMessage(rtxtLog.Handle, WM_VSCROLL, SB_BOTTOM, 0);
        }

        #endregion
    }
}